using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace Boids {
    public class Game1 : Microsoft.Xna.Framework.Game {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        Matrix worldMatrix;
        Matrix viewMatrix;
        Matrix projectionMatrix;

        BasicEffect basicEffect;
        VertexDeclaration vertexDeclaration;
        
        int pointCount = 8;
        int pointSize = 10;
        VertexPositionNormalTexture[] pointList;
        Bird[] birds;

        Random rand;

        public Game1() {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        protected override void Initialize() {
            worldMatrix = Matrix.CreateTranslation(new Vector3(-1.5f, -0.5f, 0.0f));
            viewMatrix = Matrix.CreateLookAt(
                new Vector3(0.0f, 0.0f, 7.0f),
                new Vector3(0.0f, 0.0f, 0.0f),
                Vector3.Up
                );
            projectionMatrix = Matrix.CreatePerspectiveFieldOfView(
                MathHelper.ToRadians(45),
                (float)graphics.GraphicsDevice.Viewport.Width /
                (float)graphics.GraphicsDevice.Viewport.Height,
                1.0f, 100.0f
                );

            basicEffect = new BasicEffect(graphics.GraphicsDevice, null);
            basicEffect.DiffuseColor = new Vector3(1.0f, 1.0f, 1.0f);
            basicEffect.World = worldMatrix;
            basicEffect.View = viewMatrix;
            basicEffect.Projection = projectionMatrix;

            base.Initialize();
        }
        protected override void LoadContent() {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            vertexDeclaration = new VertexDeclaration(GraphicsDevice, VertexPositionNormalTexture.VertexElements);
            GraphicsDevice.RenderState.PointSize = pointSize;
            pointList = new VertexPositionNormalTexture[pointCount];
            birds = new Bird[pointCount];
            rand = new System.Random();

            Vector3 v0 = new Vector3(0.4f, 0.4f, 0);
            for (int x = 0; x < pointList.Length / 2; x++) {
                for (int y = 0; y < 2; y++) {
                    Vector3 p0 = new Vector3(x, y, 0);
                    List<float> samples = new List<float>();
                    birds[(x * 2) + y] = new Bird(p0, v0);
                    pointList[(x * 2) + y] = new VertexPositionNormalTexture(
                        p0, Vector3.Forward, Vector2.One);
                }
            }

        }
        protected override void UnloadContent() {
        }
        protected override void Update(GameTime gameTime) {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            foreach (Bird b in birds) {
                b.sense(birds);
            }

            base.Update(gameTime);
        }
        protected override void Draw(GameTime gameTime) {
            GraphicsDevice.Clear(Color.CornflowerBlue);
            GraphicsDevice.VertexDeclaration = vertexDeclaration;

            float dt = (float) (gameTime.ElapsedGameTime.TotalMilliseconds / 1000.0f);
            for (int i = 0; i < pointList.Length; i++) {
                pointList[i].Position = birds[i].step(dt);
            }

            basicEffect.Begin();
            foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes) {
                pass.Begin();
                spriteBatch.Begin();
                GraphicsDevice.DrawUserPrimitives<VertexPositionNormalTexture>(
                    PrimitiveType.PointList, pointList, 0, pointList.Length);
                spriteBatch.End();
                pass.End();
            }

            basicEffect.End();

            base.Draw(gameTime);
        }
    }
}
